import json
import sys

from fastapi import UploadFile
from langchain_community.document_loaders import Docx2txtLoader
from langchain_core.documents import Document

from tools.chat_tools  import get_file_tools
from models.json_response  import JsonData
from typing  import List,AsyncIterator,Dict,AsyncGenerator
from langchain.agents import create_openai_functions_agent,AgentExecutor
from langchain.prompts import ChatPromptTemplate,MessagesPlaceholder
from langchain.tools import Tool
from core.llm import get_default_llm
from models.json_response import JsonData
import asyncio
from service.file_service import FileService
import logging

logger = logging.getLogger(__name__)

def create_file_agent(tools: List[Tool]):
    system_prompt = """
    你是一个教学文本归纳,请根据提供的文本生成一个课程知识点大纲，请勿重复内容，请使用中文。
        
        文本内容:{text}
        
        要求：
        1. 知识点要求全面
        2. 请严格依照传入文本内容进行总结
        3. 不要出现注释
        4. 输出严格按照格式为JSON，示例：
        {{
            "main_topic": "教学文本主题",
            "subtopics": [
                {{
                    "name": "各板块名称",
                    "subtopics": [
                        {{
                            "name": "知识点名称",
                            "content": "知识点内容",
                            "subtopics": ["关键点1", "关键点2"]
                        }}
                    ]
                }}
            ]
        }}
        """

    prompt = ChatPromptTemplate.from_messages([
        ("system", system_prompt),
        MessagesPlaceholder(variable_name="agent_scratchpad")
    ])

    llm = get_default_llm()
    agent = create_openai_functions_agent(
        llm=llm,
        tools=tools,
        prompt=prompt,
    )
    agent_executor = AgentExecutor.from_agent_and_tools(
        agent=agent,
        tools=tools,
        verbose=True,
        max_iterations=3,
        handle_parsing_errors=True,
    )
    return agent_executor

async def generate_stream_response(file_service:FileService,
                               file:List[Document])->AsyncIterator:
    agent = create_file_agent(get_file_tools())
    data = file
    text = ""
    for chunk in data:
        text += chunk.page_content
    current_chunk=""
    async for token in outline_with_agent(agent,file_service,text):
        current_chunk += token
        if token in ["\n", "\r\n","。",".","，"] or len(current_chunk) > 5:
            response = JsonData.stream_data(data=current_chunk)
            yield f"data: {response.model_dump_json()}]\n\n"
            current_chunk = ""
            await asyncio.sleep(0.1)
    if current_chunk:
        response = JsonData.stream_data(data=current_chunk)
        yield f"data: {response.model_dump_json()}]\n\n"

async def outline_with_agent(agent_executor: AgentExecutor,
                             file_service:FileService,
                             text: str) -> AsyncGenerator[str, None]:
    try:
        async for chunk in agent_executor.astream({"text": text}):
            response = chunk["output"]
            for token in response:
                yield token
                await asyncio.sleep(0.01)
    except Exception as e:
        logging.error(e)

def generate_response(file_service:FileService,
                               file:UploadFile)->AsyncIterator:
    agent = create_file_agent(get_file_tools())
    data = file_service.load_file(file)
    text = ""
    for chunk in data:
        text += chunk.page_content
    response = agent.run({"text": text})
    try:
        json_str = clean_json_string(response["output"])
        return json.loads(json_str)
    except Exception as e:
        print(f"\033[91m[错误]\033[0m JSON解析失败: {str(e)}", file=sys.stderr)
        print(f"\033[93m[调试]\033[0m 原始输出:\n{response['output']}", file=sys.stderr)
        generate_response(file_service,file)
        raise
    return response

def clean_json_string(self, text: str) -> str:
        """清理JSON字符串"""
        # 找到第一个完整的JSON对象
        start = text.find('{')
        end = -1
        brace_count = 0
        for i in range(start, len(text)):
            if text[i] == '{':
                brace_count += 1
            elif text[i] == '}':
                brace_count -= 1
                if brace_count == 0:
                    end = i + 1
                    break

        if start == -1 or end == -1:
            raise ValueError("未找到有效的JSON内容")

        json_str = text[start:end]

        # 移除代码块标记和注释
        json_str = json_str.replace('```json', '')
        json_str = json_str.replace('```', '')
        json_str = json_str.replace('/*', '')
        json_str = json_str.replace('*/', '')

        # 添加缺失的逗号
        lines = json_str.split('\n')
        processed_lines = []
        for i, line in enumerate(lines):
            line = line.strip()
            if not line:
                continue

            # 如果不是最后一行且当前行以引号结尾且下一行不是结束标记
            if i < len(lines) - 1 and line.rstrip().endswith('"') and not lines[i + 1].strip().startswith('}') and not \
            lines[i + 1].strip().startswith(']'):
                line += ','

            # 如果不是最后一行且当前行以大括号或方括号结尾且下一行不是结束标记
            if i < len(lines) - 1 and (line.rstrip().endswith('}') or line.rstrip().endswith(']')) and not lines[
                i + 1].strip().startswith('}') and not lines[i + 1].strip().startswith(']'):
                line += ','

            processed_lines.append(line)

        json_str = '\n'.join(processed_lines)

        # 确保所有属性名都有双引号
        for prop in ['title', 'slides', 'content', 'image_prompt', 'search_query']:
            json_str = json_str.replace(f'{prop}:', f'"{prop}":')
            json_str = json_str.replace(f'"{prop}" :', f'"{prop}":')

        # 确保所有字符串值都有双引号
        import re
        json_str = re.sub(r':\s*([^",\{\[\]\}\s][^",\{\[\]\}\s]*)', r': "\1"', json_str)

        return json_str